/**
 * @file bsp_rtc.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-11-23
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "bsp_rtc.h"
#include "hal_adapter.h"
#include "time.h"

extern void Error_Handler(void);


RTC_HandleTypeDef hrtc;
void rtc_init(void)
{
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    /** Initializes the peripherals clock
     */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }

    /* Peripheral clock enable */
    __HAL_RCC_RTC_ENABLE();
    __HAL_RCC_RTCAPB_CLK_ENABLE();
    __HAL_RCC_RTCAPB_CLKAM_ENABLE();
    
    RTC_PrivilegeStateTypeDef privilegeState = {0};
    /** Initialize RTC Only
     */
    hrtc.Instance = RTC;
    hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
    hrtc.Init.AsynchPrediv = 127;
    hrtc.Init.SynchPrediv = 255;
    hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
    hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
    hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
    hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
    hrtc.Init.BinMode = RTC_BINARY_NONE;
    if (HAL_RTC_Init(&hrtc) != HAL_OK)
    {
        Error_Handler();
    }

    
    privilegeState.rtcPrivilegeFull = RTC_PRIVILEGE_FULL_NO;
    privilegeState.backupRegisterPrivZone = RTC_PRIVILEGE_BKUP_ZONE_NONE;
    privilegeState.backupRegisterStartZone2 = RTC_BKP_DR0;
    privilegeState.backupRegisterStartZone3 = RTC_BKP_DR0;
    if (HAL_RTCEx_PrivilegeModeSet(&hrtc, &privilegeState) != HAL_OK)
    {
        Error_Handler();
    }

    
    /* Peripheral clock enable */
    __HAL_RCC_RTC_ENABLE();
    __HAL_RCC_RTCAPB_CLK_ENABLE();
    __HAL_RCC_RTCAPB_CLKAM_ENABLE();
    /* RTC interrupt Init */
    HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(RTC_IRQn);
}


void rtc_get_datetime(RTC_TimeTypeDef *time, RTC_DateTypeDef *date)
{
    HAL_RTC_WaitForSynchro(&hrtc);

    HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, date, RTC_FORMAT_BIN);
}


void rtc_set_datetime(RTC_TimeTypeDef *time, RTC_DateTypeDef *date)
{
    HAL_RTC_WaitForSynchro(&hrtc);

    HAL_RTC_SetTime(&hrtc, time, RTC_FORMAT_BIN);
	HAL_RTC_SetDate(&hrtc, date, RTC_FORMAT_BIN);
}




/**
 * @brief 通过rtc获取时间
*/
int32_t bsp_rtc_get(struct tm *tim)
{
    RTC_TimeTypeDef RTC_TimeStructure;
	RTC_DateTypeDef RTC_DateStructure;


	rtc_get_datetime(&RTC_TimeStructure, &RTC_DateStructure);

    tim->tm_sec = RTC_TimeStructure.Seconds;
    tim->tm_min = RTC_TimeStructure.Minutes;
    tim->tm_hour = RTC_TimeStructure.Hours;
    tim->tm_mday = RTC_DateStructure.Date;

    tim->tm_mon = RTC_DateStructure.Month + 1; //(RTC_DateStructure.Month > 0) ? (RTC_DateStructure.Month - 1) : RTC_DateStructure.Month; /* tim->tm_mon [0, 11] */
    tim->tm_year = RTC_DateStructure.Year;

    tim->tm_year += 1900;
    tim->tm_isdst = 0;

	return 0;
}


/**
 * @brief 通过外部设置RTC时间
*/
int32_t bsp_rtc_set(struct tm *tim)
{
    RTC_TimeTypeDef RTC_TimeStructure = {0};
	RTC_DateTypeDef RTC_DateStructure = {0};

    RTC_TimeStructure.Seconds = tim->tm_sec;
    RTC_TimeStructure.Minutes = tim->tm_min;
    RTC_TimeStructure.Hours = tim->tm_hour;
    RTC_DateStructure.Date = tim->tm_mday;
	RTC_DateStructure.Month = tim->tm_mon - 1; /* tim->tm_mon [1, 12] */
    RTC_DateStructure.Year = tim->tm_year - 1900;

	rtc_set_datetime(&RTC_TimeStructure, &RTC_DateStructure);

	return 0;
}

/**
  * @brief  Gets the RTC current Calendar Sub seconds value.
  * @note   This function freeze the Time and Date registers after reading the 
  *         SSR register.
  * @param  None
  * @retval RTC current Calendar Sub seconds value.
  */
uint32_t RTC_GetSubSecond(void)
{
  uint32_t tmpreg = 0;
  
  /* Get sub seconds values from the correspondent registers*/
  tmpreg = (uint32_t)(RTC->SSR);
  
  /* Read DR register to unfroze calendar registers */
  (void) (RTC->DR);
  
  return (tmpreg);
}

/**
 * @brief 
 * 
 * @return uint32_t 
 */
uint32_t bsp_rtc_subsecond_get(void)
{
    return RTC_GetSubSecond();
}




unsigned int bsp_rtc_subsecond_reload(void)
{
    return ((RTC->PRER & RTC_PRER_PREDIV_S) >> 0);
}
